﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Windows.Threading;
using System.Windows.Media.Effects;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Windows.Data;

namespace EffectLibrary {
    /// <summary>
    /// effect engine
    /// </summary>
    public class Engine {
        static Engine f1;
        public static Engine pEngine {
            get { if (f1 == null)f1 = new Engine(); return Engine.f1; }
        }
        public Engine() {
            this.pD3 = new MatrixHelp();
            this.fStoryboard = new Storyboard();
            this.fRandoms = new Random[rcount];
            for (int i = 0 ; i < rcount ; i++) {
                this.fRandoms[i] = new Random();
            }
            this.pAnimateParamBig = new List<Tuple<string,dynamic,dynamic,double,double,EasingFunctionBase,FrameworkElement>>();
            this.pAnimateParamMiddle = new List<Tuple<string,dynamic,dynamic,double,double,EasingFunctionBase>>();
            this.pAnimateParamSmall = new List<Tuple<string,dynamic,double,double,EasingFunctionBase>>();
        }
        public MatrixHelp pD3 { get; set; }
        Storyboard fStoryboard;
        #region animation

        public Storyboard GetAnimationLocal(params Tuple<string,dynamic,dynamic,double,double,EasingFunctionBase,FrameworkElement>[] data) {
            this.fStoryboard.Stop();
            this.fStoryboard.Children.Clear();
            foreach (var item in data) {
                if (item.Item2 is double && item.Item3 is double) {
                    var da = new DoubleAnimation {
                        From = item.Item2, To = item.Item3, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item4)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item5),
                        EasingFunction = item.Item6,
                    };
                    Storyboard.SetTarget(da,item.Item7);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    this.fStoryboard.Children.Add(da);
                } else if (item.Item2 is Color && item.Item3 is Color) {
                    var da = new ColorAnimation {
                        From = item.Item2, To = item.Item3, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item4)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item5),
                        EasingFunction = item.Item6,
                    };
                    Storyboard.SetTarget(da,item.Item7);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    this.fStoryboard.Children.Add(da);
                } else if (item.Item2 is Point && item.Item3 is Point) {
                    var da = new PointAnimation {
                        From = item.Item2, To = item.Item3, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item4)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item5),
                        EasingFunction = item.Item6,
                    };
                    Storyboard.SetTarget(da,item.Item7);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    this.fStoryboard.Children.Add(da);
                } else {
                    return null;
                }
            }
            return this.fStoryboard;
        }
        public Storyboard GetAnimationLocal(params Tuple<string,dynamic,double,double,EasingFunctionBase,FrameworkElement>[] data) {
            this.fStoryboard.Stop();
            this.fStoryboard.Children.Clear();
            foreach (var item in data) {
                if (item.Item2 is double) {
                    var da = new DoubleAnimation {
                        By = item.Item2, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item3)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item4),
                        EasingFunction = item.Item5,
                    };
                    Storyboard.SetTarget(da,item.Item6);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    this.fStoryboard.Children.Add(da);

                } else if (item.Item2 is Color) {
                    var da = new ColorAnimation {
                        By = item.Item2, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item3)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item4),
                        EasingFunction = item.Item5,
                    };
                    Storyboard.SetTarget(da,item.Item6);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    this.fStoryboard.Children.Add(da);
                } else if (item.Item2 is Point) {
                    var da = new PointAnimation {
                        By = item.Item2, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item3)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item4),
                        EasingFunction = item.Item5,
                    };
                    Storyboard.SetTarget(da,item.Item6);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    this.fStoryboard.Children.Add(da);
                } else {
                    return null;
                }
            }
            return this.fStoryboard;
        }
        public Storyboard GetAnimation(params Tuple<string,dynamic,dynamic,double,double,EasingFunctionBase,FrameworkElement>[] data) {
            var sb = new Storyboard();
            foreach (var item in data) {
                if (item.Item2 is double && item.Item3 is double) {
                    var da = new DoubleAnimation {
                        From = item.Item2, To = item.Item3, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item4)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item5),
                        EasingFunction = item.Item6,
                    };
                    Storyboard.SetTarget(da,item.Item7);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    sb.Children.Add(da);
                } else if (item.Item2 is Color && item.Item3 is Color) {
                    var da = new ColorAnimation {
                        From = item.Item2, To = item.Item3, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item4)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item5),
                        EasingFunction = item.Item6,
                    };
                    Storyboard.SetTarget(da,item.Item7);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    sb.Children.Add(da);
                } else if (item.Item2 is Point && item.Item3 is Point) {
                    var da = new PointAnimation {
                        From = item.Item2, To = item.Item3, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item4)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item5),
                        EasingFunction = item.Item6,
                    };
                    Storyboard.SetTarget(da,item.Item7);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    sb.Children.Add(da);
                } else {
                    return null;
                }
            }
            return sb;
        }
        public Storyboard GetAnimation(params Tuple<string,dynamic,double,double,EasingFunctionBase,FrameworkElement>[] data) {
            var sb = new Storyboard();
            foreach (var item in data) {
                if (item.Item2 is double) {
                    var da = new DoubleAnimation {
                        By = item.Item2, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item3)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item4),
                        EasingFunction = item.Item5,
                    };
                    Storyboard.SetTarget(da,item.Item6);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    sb.Children.Add(da);

                } else if (item.Item2 is Color) {
                    var da = new ColorAnimation {
                        By = item.Item2, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item3)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item4),
                        EasingFunction = item.Item5,
                    };
                    Storyboard.SetTarget(da,item.Item6);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    sb.Children.Add(da);
                } else if (item.Item2 is Point) {
                    var da = new PointAnimation {
                        By = item.Item2, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item3)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item4),
                        EasingFunction = item.Item5,
                    };
                    Storyboard.SetTarget(da,item.Item6);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    sb.Children.Add(da);
                } else {
                    return null;
                }
            }
            return sb;
        }
        public Storyboard GetAnimationLocal(FrameworkElement target,params Tuple<string,dynamic,dynamic,double,double,EasingFunctionBase>[] data) {
            this.fStoryboard.Stop();
            this.fStoryboard.Children.Clear();
            foreach (var item in data) {
                if (item.Item2 is double && item.Item3 is double) {
                    var da = new DoubleAnimation {
                        From = item.Item2, To = item.Item3, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item4)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item5),
                        EasingFunction = item.Item6,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    this.fStoryboard.Children.Add(da);
                } else if (item.Item2 is Color && item.Item3 is Color) {
                    var da = new ColorAnimation {
                        From = item.Item2, To = item.Item3, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item4)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item5),
                        EasingFunction = item.Item6,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    this.fStoryboard.Children.Add(da);
                } else if (item.Item2 is Point && item.Item3 is Point) {
                    var da = new PointAnimation {
                        From = item.Item2, To = item.Item3, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item4)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item5),
                        EasingFunction = item.Item6,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    this.fStoryboard.Children.Add(da);
                } else {
                    return null;
                }
            }
            return this.fStoryboard;
        }
        public Storyboard GetAnimationLocal(FrameworkElement target,params Tuple<string,dynamic,double,double,EasingFunctionBase>[] data) {
            this.fStoryboard.Stop();
            this.fStoryboard.Children.Clear();
            foreach (var item in data) {
                if (item.Item2 is double) {
                    var da = new DoubleAnimation {
                        By = item.Item2, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item3)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item4),
                        EasingFunction = item.Item5,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    this.fStoryboard.Children.Add(da);

                } else if (item.Item2 is Color) {
                    var da = new ColorAnimation {
                        By = item.Item2, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item3)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item4),
                        EasingFunction = item.Item5,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    this.fStoryboard.Children.Add(da);
                } else if (item.Item2 is Point) {
                    var da = new PointAnimation {
                        By = item.Item2, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item3)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item4),
                        EasingFunction = item.Item5,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    this.fStoryboard.Children.Add(da);
                } else {
                    return null;
                }
            }
            return this.fStoryboard;
        }
        public Storyboard GetAnimation(FrameworkElement target,params Tuple<string,dynamic,dynamic,double,double,EasingFunctionBase>[] data) {
            var sb = new Storyboard();
            foreach (var item in data) {
                if (item.Item2 is double && item.Item3 is double) {
                    var da = new DoubleAnimation {
                        From = item.Item2, To = item.Item3, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item4)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item5),
                        EasingFunction = item.Item6,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    sb.Children.Add(da);
                } else if (item.Item2 is Color && item.Item3 is Color) {
                    var da = new ColorAnimation {
                        From = item.Item2, To = item.Item3, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item4)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item5),
                        EasingFunction = item.Item6,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    sb.Children.Add(da);
                } else if (item.Item2 is Point && item.Item3 is Point) {
                    var da = new PointAnimation {
                        From = item.Item2, To = item.Item3, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item4)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item5),
                        EasingFunction = item.Item6,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    sb.Children.Add(da);
                } else {
                    return null;
                }
            }
            return sb;
        }
        public Storyboard GetAnimation(FrameworkElement target,params Tuple<string,dynamic,double,double,EasingFunctionBase>[] data) {
            var sb = new Storyboard();
            foreach (var item in data) {
                if (item.Item2 is double) {
                    var da = new DoubleAnimation {
                        By = item.Item2, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item3)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item4),
                        EasingFunction = item.Item5,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    sb.Children.Add(da);

                } else if (item.Item2 is Color) {
                    var da = new ColorAnimation {
                        By = item.Item2, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item3)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item4),
                        EasingFunction = item.Item5,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    sb.Children.Add(da);
                } else if (item.Item2 is Point) {
                    var da = new PointAnimation {
                        By = item.Item2, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item3)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item4),
                        EasingFunction = item.Item5,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    sb.Children.Add(da);
                } else {
                    return null;
                }
            }
            return sb;
        }
        public Storyboard GetAnimationLocal(FrameworkElement target,double iterate,params Tuple<string,dynamic,dynamic,double,double,EasingFunctionBase>[] data) {
            this.fStoryboard.Stop();
            this.fStoryboard.Children.Clear();
            this.fStoryboard.RepeatBehavior = new RepeatBehavior(iterate);
            foreach (var item in data) {
                if (item.Item2 is double && item.Item3 is double) {
                    var da = new DoubleAnimation {
                        From = item.Item2, To = item.Item3, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item4)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item5),
                        EasingFunction = item.Item6,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    this.fStoryboard.Children.Add(da);

                } else if (item.Item2 is Color && item.Item3 is Color) {
                    var da = new ColorAnimation {
                        From = item.Item2, To = item.Item3, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item4)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item5),
                        EasingFunction = item.Item6,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    this.fStoryboard.Children.Add(da);
                } else if (item.Item2 is Point && item.Item3 is Point) {
                    var da = new PointAnimation {
                        From = item.Item2, To = item.Item3, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item4)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item5),
                        EasingFunction = item.Item6,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    this.fStoryboard.Children.Add(da);
                } else {
                    return null;
                }
            }
            return this.fStoryboard;
        }
        public Storyboard GetAnimationLocal(FrameworkElement target,double iterate,params Tuple<string,dynamic,double,double,EasingFunctionBase>[] data) {
            this.fStoryboard.Stop();
            this.fStoryboard.Children.Clear();
            this.fStoryboard.RepeatBehavior = new RepeatBehavior(iterate);
            foreach (var item in data) {
                if (item.Item2 is double) {
                    var da = new DoubleAnimation {
                        By = item.Item2, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item3)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item4),
                        EasingFunction = item.Item5,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    this.fStoryboard.Children.Add(da);

                } else if (item.Item2 is Color) {
                    var da = new ColorAnimation {
                        By = item.Item2, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item3)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item4),
                        EasingFunction = item.Item5,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    this.fStoryboard.Children.Add(da);
                } else if (item.Item2 is Point) {
                    var da = new PointAnimation {
                        By = item.Item2, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item3)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item4),
                        EasingFunction = item.Item5,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    this.fStoryboard.Children.Add(da);
                } else {
                    return null;
                }
            }
            return this.fStoryboard;
        }
        public Storyboard GetAnimation(FrameworkElement target,double iterate,params Tuple<string,dynamic,dynamic,double,double,EasingFunctionBase>[] data) {
            var sb = new Storyboard();
            sb.RepeatBehavior = new RepeatBehavior(iterate);
            foreach (var item in data) {
                if (item.Item2 is double && item.Item3 is double) {
                    var da = new DoubleAnimation {
                        From = item.Item2, To = item.Item3, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item4)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item5),
                        EasingFunction = item.Item6,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    sb.Children.Add(da);

                } else if (item.Item2 is Color && item.Item3 is Color) {
                    var da = new ColorAnimation {
                        From = item.Item2, To = item.Item3, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item4)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item5),
                        EasingFunction = item.Item6,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    sb.Children.Add(da);
                } else if (item.Item2 is Point && item.Item3 is Point) {
                    var da = new PointAnimation {
                        From = item.Item2, To = item.Item3, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item4)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item5),
                        EasingFunction = item.Item6,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    sb.Children.Add(da);
                } else {
                    return null;
                }
            }
            return sb;
        }
        public Storyboard GetAnimation(FrameworkElement target,double iterate,params Tuple<string,dynamic,double,double,EasingFunctionBase>[] data) {
            var sb = new Storyboard();
            sb.RepeatBehavior = new RepeatBehavior(iterate);
            foreach (var item in data) {
                if (item.Item2 is double) {
                    var da = new DoubleAnimation {
                        By = item.Item2, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item3)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item4),
                        EasingFunction = item.Item5,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    sb.Children.Add(da);

                } else if (item.Item2 is Color) {
                    var da = new ColorAnimation {
                        By = item.Item2, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item3)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item4),
                        EasingFunction = item.Item5,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    sb.Children.Add(da);
                } else if (item.Item2 is Point) {
                    var da = new PointAnimation {
                        By = item.Item2, Duration = new Duration(TimeSpan.FromMilliseconds(item.Item3)),
                        BeginTime = TimeSpan.FromMilliseconds(item.Item4),
                        EasingFunction = item.Item5,
                    };
                    Storyboard.SetTarget(da,target);
                    Storyboard.SetTargetProperty(da,new PropertyPath(item.Item1));
                    sb.Children.Add(da);
                } else {
                    return null;
                }
            }
            return sb;
        }

        #endregion
        //
        public Tuple<string,dynamic,dynamic,double,double,EasingFunctionBase,FrameworkElement> GetAnimateParam(FrameworkElement target,string fe,dynamic start,dynamic end,double duration,double begintime = 0.0,EasingFunctionBase efb = null) {
            return Tuple.Create<string,dynamic,dynamic,double,double,EasingFunctionBase,FrameworkElement>(fe,start,end,duration,begintime,efb,target);
        }
        public Tuple<string,dynamic,dynamic,double,double,EasingFunctionBase> GetAnimateParam(string fe,dynamic start,dynamic end,double duration,double begintime = 0.0,EasingFunctionBase efb = null) {
            return Tuple.Create<string,dynamic,dynamic,double,double,EasingFunctionBase>(fe,start,end,duration,begintime,efb);
        }
        public Tuple<string,dynamic,double,double,EasingFunctionBase> GetAnimateParam(string fe,dynamic by,double duration,double bgtime,EasingFunctionBase efb = null) {
            return Tuple.Create<string,dynamic,double,double,EasingFunctionBase>(fe,by,duration,bgtime,efb);
        }
        //
        public PlaneProjection GetProjection(double crx = .5,double cry = .5,double crz = 0.0,double rx = 0.0,double ry = 0.0,double rz = 0.0,double lox = 0.0,double loy = 0.0,double loz = 0.0,double gox = 0,double goy = 0,double goz = 0.0) {
            var pp = new PlaneProjection {
                CenterOfRotationX = crx,
                CenterOfRotationY = cry,
                CenterOfRotationZ = crz,
                GlobalOffsetX = gox,
                GlobalOffsetY = goy,
                GlobalOffsetZ = goz,
                LocalOffsetX = lox,
                LocalOffsetY = loy,
                LocalOffsetZ = loz,
                RotationX = rx,
                RotationY = ry,
                RotationZ = rz,
            };
            return pp;
        }
        Projection fProjection;
        public PlaneProjection GetProjectionLocal(double crx = 0.5,double cry = 0.5,double crz = 0.0,double rx = 0.0,double ry = 0.0,double rz = 0.0,double lox = 0.0,double loy = 0.0,double loz = 0.0,double gox = 0,double goy = 0,double goz = 0.0) {
            var pp = new PlaneProjection {
                CenterOfRotationX = crx,
                CenterOfRotationY = cry,
                CenterOfRotationZ = crz,
                GlobalOffsetX = gox,
                GlobalOffsetY = goy,
                GlobalOffsetZ = goz,
                LocalOffsetX = lox,
                LocalOffsetY = loy,
                LocalOffsetZ = loz,
                RotationX = rx,
                RotationY = ry,
                RotationZ = rz,
            };
            this.fProjection = pp;
            return (PlaneProjection)this.fProjection;
        }

        /// <summary>
        /// 仿真数据暂存
        /// </summary>
        public dynamic pDynamicDatas { get; set; }
        DispatcherTimer fDispatcherTimer;
        public void Start(double milliseconds,EventHandler tick) {
            if (this.fDispatcherTimer == null) {
                this.fDispatcherTimer = new DispatcherTimer();
                this.fDispatcherTimer.Interval = TimeSpan.FromMilliseconds(milliseconds);
                this.fDispatcherTimer.Tick += tick;
            } else {
                this.fDispatcherTimer.Interval = TimeSpan.FromMilliseconds(milliseconds);
                this.fDispatcherTimer.Tick += tick;
            }
            this.fDispatcherTimer.Start();
        }
        public void Stop() {
            if (this.fDispatcherTimer != null) {
                this.fDispatcherTimer.Stop();
            }
        }
        /// <summary>
        /// string:path
        /// Item2_dynamic:From
        /// Item3_dynamic:To
        /// Item4_double:Duration
        /// Item5_double:BeginTime
        /// </summary>
        public List<Tuple<string,dynamic,dynamic,double,double,EasingFunctionBase,FrameworkElement>> pAnimateParamBig { get; set; }
        public List<Tuple<string,dynamic,dynamic,double,double,EasingFunctionBase>> pAnimateParamMiddle { get; set; }
        public List<Tuple<string,dynamic,double,double,EasingFunctionBase>> pAnimateParamSmall { get; set; }
        public DispatcherTimer BuildTimer(double milliseconds,EventHandler tick) {
            var dt = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(milliseconds) };
            dt.Tick += tick;
            return dt;
        }
        public void DelayPerformance(double milliseconds,Action<dynamic> task,dynamic taskparameter = default(dynamic)) {
            var dt = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(milliseconds) };
            dt.Tick += (o,k) => {
                var timer = o as DispatcherTimer;
                task.Invoke(taskparameter);
                timer.Stop();
            };
            dt.Start();
        }
        //
        Random[] fRandoms; const byte rcount = 3;
        Random mGetRan(bool isFixed = false,byte i = 0) {
            if (!isFixed)
                return this.fRandoms[new Random().Next(0,rcount)];
            else
                return this.fRandoms[i];
        }
        public ChartDataItem[] GetChartData(Func<double,double> func,bool isRandom = true,int num = 100,int rang = 1000) {
            //正负1k内的 double值 函数
            if (num < 10) num = 10;
            if (rang < 100) rang = 100;
            var r = new ChartDataItem[num];
            double x,y;
            x = y = 0;
            if (isRandom) {
                for (int i = 0 ; i < num ; i++) {
                    x = this.mGetRan(true).Next(-rang,rang);
                    x += this.mGetRan(true,1).NextDouble();
                    y = func.Invoke(x);
                    r[i] = new ChartDataItem { pX = x,pY = y };
                }
            } else {
                double cell = (rang - (-rang)) / num;
                for (int i = 0 ; i < num ; i++) {
                    x = (-rang) + i * cell;
                    y = func.Invoke(x);
                    r[i] = new ChartDataItem { pX = x,pY = y };
                }
            }
            return r;
        }
        /// <summary>
        /// 内置驱动线程
        /// </summary>
        /// <param name="func"></param>
        /// <param name="step"></param>
        /// <param name="num"></param>
        /// <param name="rang"></param>
        /// <param name="ms"></param>
        public void RunChartData(Func<double,double> func,double step = 1.0,double stepr = 1.0,int num = 100,int rang = 1000,double ms = 800) {
            //正负1k内的 double值 函数
            if (num < 10) num = 10;
            if (rang < 100) rang = 100;
            this.fChartSource.pChartDataItems = new ObservableCollection<ChartDataItem>();
            for (int i = 0 ; i < num ; i++) {
                this.fChartSource.pChartDataItems.Add(new ChartDataItem());
            }
            double cell = (rang - (-rang)) / num;
            var timemark = step;
            sbyte key = 1;
            double vv = step;
            this.Stop();
            this.Start(ms,(s,e) => {
                if (vv > stepr) {
                    key = -1;
                } else if (vv < -stepr) {
                    key = 1;
                }
                vv += key * step;
                for (int i = 0 ; i < num ; i++) {
                    this.fChartSource.pChartDataItems[i].pX = (-rang) + (i + vv) * cell;
                    this.fChartSource.pChartDataItems[i].pY = func.Invoke(this.fChartSource.pChartDataItems[i].pX);
                }
            });
        }

        /// <summary>
        /// 内置驱动线程
        /// </summary>
        /// <param name="func"></param>
        /// <param name="step"></param>
        /// <param name="num"></param>
        /// <param name="rang"></param>
        /// <param name="ms"></param>
        public Binding GetChartDataItemsSource(Func<double,double> func,double step = 1.0,double stepr = 1.0,int num = 100,int rang = 1000,double ms = 800) {
            //正负1k内的 double值 函数
            if (num < 10) num = 10;
            if (rang < 100) rang = 100;
            this.fChartSource.pChartDataItems = new ObservableCollection<ChartDataItem>();
            for (int i = 0 ; i < num ; i++) {
                this.fChartSource.pChartDataItems.Add(new ChartDataItem());
            }
            double cell = (rang - (-rang)) / num;
            sbyte key = 1;
            double vv = step;
            this.Stop();
            this.Start(ms,(s,e) => {
                if (vv > stepr) {
                    key = -1;
                } else if (vv < -stepr) {
                    key = 1;
                }
                vv += key * step;
                for (int i = 0 ; i < num ; i++) {
                    this.fChartSource.pChartDataItems[i].pX = (-rang) + (i + vv) * cell;
                    this.fChartSource.pChartDataItems[i].pY = func.Invoke(this.fChartSource.pChartDataItems[i].pX);
                }
            });
            var r = new Binding {
                Mode = BindingMode.TwoWay,
                Source = this.fChartSource,
                Path = new PropertyPath("pChartDataItems"),
            };
            return r;
        }
        public class ChartDataItem : INotifyPropertyChanged {
            double f1;
            public double pX {
                get { return f1; }
                set { f1 = value; this.OnPropertyChanged("pX"); }
            }
            double f2;
            public double pY {
                get { return f2; }
                set { f2 = value; this.OnPropertyChanged("pY"); }
            }
            bool f3;
            public bool IsNormal {
                get { return f3; }
                set { f3 = value; this.OnPropertyChanged("IsNormal"); }
            }

            #region INotifyPropertyChanged 成员

            public event PropertyChangedEventHandler PropertyChanged;
            void OnPropertyChanged(string pn) {
                if (this.PropertyChanged != null) {
                    this.PropertyChanged.Invoke(this,new PropertyChangedEventArgs(pn));
                }
            }
            #endregion
        }
        public class ChartSource {
            ObservableCollection<ChartDataItem> f1;
            public ObservableCollection<ChartDataItem> pChartDataItems {
                get { return f1; }
                set { f1 = value; this.OnPropertyChanged("pChartDataItems"); }
            }

            #region INotifyPropertyChanged 成员

            public event PropertyChangedEventHandler PropertyChanged;
            void OnPropertyChanged(string pn) {
                if (this.PropertyChanged != null) {
                    this.PropertyChanged.Invoke(this,new PropertyChangedEventArgs(pn));
                }
            }
            #endregion
        }
        public ChartSource fChartSource = new ChartSource();
        //
        Border GetCard(int text,SolidColorBrush sb) {
            var b = new Border { Width = 150d,Height = 200d,BorderBrush = sb,BorderThickness = new Thickness(2.8),Background = new SolidColorBrush(Colors.White),CornerRadius = new CornerRadius(10) };
            var sp = new StackPanel { Margin = new Thickness(16),HorizontalAlignment = HorizontalAlignment.Stretch,VerticalAlignment = VerticalAlignment.Stretch };
            var tb = new TextBlock { FontSize = 16,Text = text.ToString(),Margin = new Thickness(10,0,0,0),FontWeight = FontWeights.ExtraBold };
            var tb2 = new TextBlock { FontSize = 16,Text = text.ToString(),Margin = new Thickness(0,0,10,0),FontWeight = FontWeights.ExtraBold,HorizontalAlignment = HorizontalAlignment.Right };
            var e = new Ellipse { Fill = sb,Width = 80,Height = 110,HorizontalAlignment = HorizontalAlignment.Center,VerticalAlignment = VerticalAlignment.Center };
            sp.Children.Add(tb);
            sp.Children.Add(e);
            sp.Children.Add(tb2);
            b.Child = sp;
            return b;
        }
        public enum StaticDataType {
            单位索引, 单位随机小数列, 索引和随机小数列, 索引和正弦函数列, 索引和余弦函数列, 人员表, 随机单色矩形, 随机杂色矩形, 随机单色椭圆, 索引正余弦数列, 索引百内三随机, 索引百内五随机, 索引千内六随机, 自定义函数数列, 顺序卡片
        }
        /// <summary>
        /// 为dynamic：pTestData充值 使用Tuple<T,...>方案
        /// </summary>
        /// <returns>表的列数</returns>
        public int GetStaticData(StaticDataType sdt = StaticDataType.自定义函数数列,int count = 100,Func<double,double> func = null) {
            int column = 1;
            if (count < 5 || count > 10000) {
                count = 100;
            }
            if (func != null) {
                var sk = mGetRan().Next(0,10) + mGetRan().NextDouble();
                column = 2;
                List<Tuple<double,double>> data = new List<Tuple<double,double>>();
                for (int i = 0 ; i < count ; i++) {
                    data.Add(Tuple.Create<double,double>(i * sk,func.Invoke(i * sk)));
                }
                this.pDynamicDatas = data;
            } else {
                //随机弦变辐度
                var step = 2 * Math.PI / this.mGetRan(true).Next(1,361);
                var rectw = this.mGetRan(true).Next(80,200);
                var recth = this.mGetRan(true).Next(80,200);
                Color[] cs = new[] { Colors.Black,Colors.Blue,Colors.Brown,Colors.Cyan,Colors.DarkGray,Colors.Gray,Colors.Green,Colors.LightGray,Colors.Magenta,Colors.Orange,Colors.Purple,Colors.Red,Colors.Transparent,Colors.White,Colors.Yellow };
                var clen = cs.Length;
                var bb = new SolidColorBrush(cs[this.mGetRan(true,1).Next(0,clen)]);
                var xing = new[] { 
                    "张","王","李","赵","孙","黄","毛","符","祝","曾","江","陈","雷","田","周","梁","翁","唐","钱","胡","葛","范"
                };
                var qxing = new[] { "老","小" };
                var xlen = xing.Length;
                var sex = new[] { "男","女" };

                switch (sdt) {
                    case StaticDataType.单位索引:
                    column = 1;
                    var data1 = new List<int>();
                    for (int i = 0 ; i < count ; i++) {
                        data1.Add(i);
                    }
                    this.pDynamicDatas = data1;
                    break;
                    case StaticDataType.单位随机小数列:
                    column = 1;
                    var data2 = new List<double>();
                    for (int i = 0 ; i < count ; i++) {
                        data2.Add(this.mGetRan(true).NextDouble());
                    }
                    this.pDynamicDatas = data2;
                    break;
                    case StaticDataType.索引和随机小数列:
                    column = 2;
                    List<Tuple<int,double>> data3 = new List<Tuple<int,double>>();
                    for (int i = 0 ; i < count ; i++) {
                        data3.Add(Tuple.Create<int,double>(i,this.mGetRan(true).NextDouble()));
                    }
                    this.pDynamicDatas = data3;
                    break;
                    case StaticDataType.索引和正弦函数列:
                    column = 2;
                    List<Tuple<int,double>> data4 = new List<Tuple<int,double>>();
                    for (int i = 0 ; i < count ; i++) {
                        data4.Add(Tuple.Create<int,double>(i,Math.Sin(i * step)));
                    }
                    this.pDynamicDatas = data4;
                    break;
                    case StaticDataType.索引和余弦函数列:
                    column = 2;
                    List<Tuple<int,double>> data5 = new List<Tuple<int,double>>();
                    for (int i = 0 ; i < count ; i++) {
                        data5.Add(Tuple.Create<int,double>(i,Math.Cos(i * step)));
                    }
                    this.pDynamicDatas = data5;
                    break;
                    case StaticDataType.人员表:
                    column = 7;
                    List<Tuple<string,string,string,string,string,string,string>> data6 = new List<Tuple<string,string,string,string,string,string,string>>();
                    for (int i = 0 ; i < count ; i++) {
                        data6.Add(Tuple.Create<string,string,string,string,string,string,string>(
                        qxing[mGetRan().Next(0,2)] + xing[mGetRan().Next(0,xlen)] + mGetRan().Next(100,1000).ToString(),
                        sex[mGetRan().Next(0,2)],
                        mGetRan().Next(150,200).ToString(),//身高
                        mGetRan().Next(40,120).ToString(),//体重
                        mGetRan().Next(18,55).ToString(),//年龄
                        mGetRan().Next(1,31).ToString(),//所在省分编码
                        mGetRan().Next(0,100).ToString()//分数
                        ));
                    }
                    this.pDynamicDatas = data6;
                    break;
                    case StaticDataType.随机单色矩形:
                    column = 1;
                    var data7 = new List<Rectangle>();
                    for (int i = 0 ; i < count ; i++) {
                        data7.Add(new Rectangle { Width = rectw,Height = recth,Fill = bb });
                    }
                    this.pDynamicDatas = data7;
                    break;
                    case StaticDataType.随机杂色矩形:
                    column = 1;
                    var data8 = new List<Rectangle>();
                    for (int i = 0 ; i < count ; i++) {
                        var bb2 = new SolidColorBrush(cs[this.mGetRan(true,1).Next(0,clen)]);
                        data8.Add(new Rectangle { Width = rectw,Height = recth,Fill = bb2 });
                    }
                    column = 2;
                    this.pDynamicDatas = data8;
                    break;
                    case StaticDataType.随机单色椭圆:
                    column = 1;
                    var data9 = new List<Ellipse>();
                    for (int i = 0 ; i < count ; i++) {
                        data9.Add(new Ellipse { Width = rectw,Height = recth,Fill = bb });
                    }
                    this.pDynamicDatas = data9;
                    break;
                    case StaticDataType.索引正余弦数列:
                    column = 3;
                    List<Tuple<int,double,double>> data10 = new List<Tuple<int,double,double>>();
                    for (int i = 0 ; i < count ; i++) {
                        data10.Add(Tuple.Create<int,double,double>(i,Math.Sin(i * step),Math.Cos(i * step)));
                    }
                    this.pDynamicDatas = data10;
                    break;
                    case StaticDataType.索引百内三随机:
                    column = 4;
                    List<Tuple<int,double,double,double>> data11 = new List<Tuple<int,double,double,double>>();
                    for (int i = 0 ; i < count ; i++) {
                        data11.Add(Tuple.Create<int,double,double,double>(
                        i,
                        this.mGetRan().Next(0,99) + this.mGetRan().NextDouble(),
                        this.mGetRan().Next(0,99) + this.mGetRan().NextDouble(),
                        this.mGetRan().Next(0,99) + this.mGetRan().NextDouble()
                        ));
                    }
                    this.pDynamicDatas = data11;
                    break;
                    case StaticDataType.索引百内五随机:
                    column = 6;
                    List<Tuple<int,double,double,double,double,double>> data12 = new List<Tuple<int,double,double,double,double,double>>();
                    for (int i = 0 ; i < count ; i++) {
                        data12.Add(Tuple.Create<int,double,double,double,double,double>(
                        i,
                        this.mGetRan().Next(0,99) + this.mGetRan().NextDouble(),
                        this.mGetRan().Next(0,99) + this.mGetRan().NextDouble(),
                        this.mGetRan().Next(0,99) + this.mGetRan().NextDouble(),
                        this.mGetRan().Next(0,99) + this.mGetRan().NextDouble(),
                        this.mGetRan().Next(0,99) + this.mGetRan().NextDouble()
                        ));
                    }
                    this.pDynamicDatas = data12;
                    break;
                    case StaticDataType.索引千内六随机:
                    column = 7;
                    List<Tuple<int,double,double,double,double,double,double>> data13 = new List<Tuple<int,double,double,double,double,double,double>>();
                    for (int i = 0 ; i < count ; i++) {
                        data13.Add(Tuple.Create<int,double,double,double,double,double,double>(
                        i,
                        this.mGetRan().Next(0,999) + this.mGetRan().NextDouble(),
                        this.mGetRan().Next(0,999) + this.mGetRan().NextDouble(),
                        this.mGetRan().Next(0,999) + this.mGetRan().NextDouble(),
                        this.mGetRan().Next(0,999) + this.mGetRan().NextDouble(),
                        this.mGetRan().Next(0,999) + this.mGetRan().NextDouble(),
                        this.mGetRan().Next(0,999) + this.mGetRan().NextDouble()
                        ));
                    }
                    this.pDynamicDatas = data13;
                    break;
                    case StaticDataType.顺序卡片:
                    column = 1;
                    var data14 = new List<Border>();
                    for (int i = 0 ; i < count ; i++) {
                        data14.Add(this.GetCard(i,bb));
                    }
                    this.pDynamicDatas = data14;
                    break;
                    default:
                    break;
                }
            }
            return column;
        }
        //
        Effect fEffect;
        Transform fRenderTransform;
        /// <summary>
        /// 取得BlurEffect
        /// </summary>
        /// <param name="radius"></param>
        /// <returns></returns>
        public Effect GetBlurEffect(double radius = 5) {
            this.fEffect = new BlurEffect { Radius = radius };
            return this.fEffect;
        }
        /// <summary>
        /// 取得DropShadowEffect
        /// </summary>
        /// <param name="color">可以传null代表默认值黑色</param>
        /// <param name="direction"></param>
        /// <param name="opacity"></param>
        /// <param name="shadowDepth"></param>
        /// <param name="blurRadius"></param>
        /// <returns></returns>
        public Effect GetDropShadowEffect(Color? color,double direction = 315,double opacity = 1,double shadowDepth = 5,double blurRadius = 5) {
            this.fEffect = new DropShadowEffect { Color = color == null ? Colors.Black : color.Value,Direction = direction,Opacity = opacity,ShadowDepth = shadowDepth,BlurRadius = blurRadius };
            return this.fEffect;
        }
        public Transform GetTranslateTransformLocal(double x,double y) {
            this.fRenderTransform = new TranslateTransform { X = x,Y = y };
            return this.fRenderTransform;
        }
        public Transform GetScaleTransformLocal(double scalex,double scaley,double centerx = 0.0d,double centery = 0.0d) {
            this.fRenderTransform = new ScaleTransform { CenterX = centerx,CenterY = centery,ScaleX = scalex,ScaleY = scaley };
            return this.fRenderTransform;
        }
        public Transform GetRotateTransformLocal(double angle,double centerx = 0.0d,double centery = 0.0d) {
            this.fRenderTransform = new RotateTransform { Angle = angle,CenterX = centerx,CenterY = centery };
            return this.fRenderTransform;
        }
        public Transform GetSkewTransformLocal(double anglex,double angley,double centerx = 0.0d,double centery = 0.0d) {
            this.fRenderTransform = new SkewTransform { AngleX = anglex,AngleY = angley,CenterX = centerx,CenterY = centery };
            return this.fRenderTransform;
        }
        public Transform GetMatrixTransformLocal(double m11 = 1.0,double m12 = 0.0,double m21 = 0.0,double m22 = 1.0,double offsetX = 0.0,double offsetY = 0.0) {
            this.fRenderTransform = new MatrixTransform { Matrix = new Matrix(m11,m12,m21,m22,offsetX,offsetY) };
            return this.fRenderTransform;
        }
        public Transform GetMatrixTransform(double m11 = 1.0,double m12 = 0.0,double m21 = 0.0,double m22 = 1.0,double offsetX = 0.0,double offsetY = 0.0) {
            return new MatrixTransform { Matrix = new Matrix(m11,m12,m21,m22,offsetX,offsetY) };
        }
        public CompositeTransform GetCompositeTransform(double rotation = 0,double scalex = 1.0,double scaley = 1.0,double skewx = 0,double skewy = 0,double translatex = 0,double translatey = 0,double centerx = 0,double centery = 0) {
            this.fRenderTransform = new CompositeTransform {
                Rotation = rotation, ScaleX = scalex,
                ScaleY = scaley, SkewX = skewx,
                SkewY = skewy, TranslateX = translatex,
                TranslateY = translatey,
                CenterX = centerx, CenterY = centery
            };
            return (CompositeTransform)this.fRenderTransform;
        }
        public Transform GetScaleTransform(double scalex,double scaley,double centerx = 0.0d,double centery = 0.0d) {
            return new ScaleTransform { CenterX = centerx,CenterY = centery,ScaleX = scalex,ScaleY = scaley };
        }
        public Transform GetTranslateTransform(double x,double y) {
            return new TranslateTransform { X = x,Y = y };
        }
        public Transform GetSkewTransform(double anglex,double angley,double centerx = 0.0d,double centery = 0.0d) {
            return new SkewTransform { AngleX = anglex,AngleY = angley,CenterX = centerx,CenterY = centery };
        }
        public Transform GetRotateTransform(double angle,double centerx = 0.0d,double centery = 0.0d) {
            return new RotateTransform { Angle = angle,CenterX = centerx,CenterY = centery };
        }
    }
}
